package mq

import (
	"github.com/spf13/viper"
	"github.com/streadway/amqp"
)

// 格式	amqp://账号：密码@rabbitmq服务器地址：端口号/vhost

type RabbitMQ struct {
	conn    *amqp.Connection
	channel *amqp.Channel
	//队列名字
	QueueName string
	//交换机
	Exchange string
	//key
	Key string
	//连接信息
	Mqurl string
}

func NewRabbitMQ(queueName, exchange, key string) (*RabbitMQ, error) {
	rabbitmq := &RabbitMQ{
		QueueName: queueName,
		Exchange:  exchange,
		Key:       key,
		Mqurl:     viper.GetString("rabbitmq.dsn"),
	}

	var err error
	//创建rabbitmq连接
	if rabbitmq.conn, err = amqp.Dial(rabbitmq.Mqurl); err != nil {
		return nil, err
	}
	rabbitmq.channel, err = rabbitmq.conn.Channel()
	return rabbitmq, err
}

// 路由模式：1.创建实例
func NewRabbitMQRouting(queueName, exchangeName, routingKey string) (*RabbitMQ, error) {
	return NewRabbitMQ(queueName, exchangeName, routingKey)
}

// 断开连接
func (r *RabbitMQ) Destroy() {
	r.conn.Close()
	r.channel.Close()
}

// 路由模式：2.创建channel
func (r *RabbitMQ) InitExchange() error {
	//1.尝试创建交换机
	if err := r.channel.ExchangeDeclare(
		r.Exchange,
		"direct", //直接类型
		true,
		false,
		//true表示这个exchange不可以被client用来推送消息，仅用来进行exchange和exchange之间的绑定
		false,
		false,
		nil,
	); err != nil {
		return err
	}

	//设置消息确认,生产者
	//r.channel.Confirm(false)
	//confirems := r.channel.NotifyPublish(make(chan amqp.Confirmation, 1))
	//go func() {
	//	for confirm := range confirems {
	//		if confirm.Ack { //消息已确认
	//			fmt.Printf("confirmed delivery with delivery tag: %d \n", confirm.DeliveryTag)
	//		} else { //未确认的消息可以重新发送
	//			fmt.Printf("failed confirmed delivery of delivery tag: %d \n", confirm.DeliveryTag)
	//		}
	//	}
	//}()
	return nil
}
func (r *RabbitMQ) PublishMsg(msg string) error {
	//2.发送消息
	err := r.channel.Publish(
		r.Exchange,
		r.Key, //要设置
		false,
		false,
		amqp.Publishing{
			DeliveryMode: amqp.Persistent,
			ContentType:  "text/plain", //纯文本
			Body:         []byte(msg),
		},
	)
	return err
}

// 路由模式：3.消费
func (r *RabbitMQ) RecieveRouting() (<-chan amqp.Delivery, error) {
	//2.申请队列，如果队列不存在会自动创建，如果存在则跳过创建
	//保证队列存在，消息能发送到队列中
	var (
		q   amqp.Queue
		err error
	)
	if q, err = r.channel.QueueDeclare(
		"reback_order.queue", //随机生产队伍名称
		true,
		false,
		false,
		false,
		nil,
	); err != nil {
		return nil, err
	}

	//3.绑定队列到exchange中
	if err = r.channel.QueueBind(
		q.Name,
		r.Key,
		r.Exchange,
		false,
		nil,
	); err != nil {
		return nil, err
	}

	//4.消费
	msgs, err := r.channel.Consume(
		q.Name,
		"",
		false, //自动应答
		false,
		false,
		false,
		nil,
	)
	if err != nil {
		return nil, err
	}

	return msgs, nil
}
